package g11.action;

import g11.actionutil.PatientUtilImpl;
import g11.dao.DAOException;
import g11.dao.EmployeeDAO;
import g11.dao.EmployeeDAOImpl;
import g11.dao.PatientAssignmentDAO;
import g11.dao.PatientAssignmentDAOImpl;
import g11.dao.PatientDAO;
import g11.dao.PatientDAOImpl;
import g11.dao.WorkForDAO;
import g11.dao.WorkForDAOImpl;
import g11.model.Employee;
import g11.model.Patient;
import g11.model.PatientAssignment;
import g11.model.User;

import java.sql.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

import com.opensymphony.xwork2.ActionSupport;

public class PatientAction extends ActionSupport implements SessionAware,
		RequestAware {

	private Map<String, Object> session;
	private String actionMode;

	public String getSearchContent() {
		return searchContent;
	}

	public void setSearchContent(String searchContent) {
		this.searchContent = searchContent;
	}

	public String getValue() {
		return value;
	}

	public void setValue(String value) {
		this.value = value;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	// Used for patient who have logged in
	private Patient retrievedPatient;
	private Employee defaultDoctor;

	// used for patient List page
	private String selectedPatientId;

	// Used when employee is currentUser
	// doctor or staff who has logged in and want to see his patients
	private String selectedEmployeeId;
	private List<Patient> ownerPatients;
	private Map<Patient, Employee> viewerPatients;

	// Used when create/update patient
	private List<Employee> retrievedDoctors;
	// private String selectedDefaultDoctorId;
	private String selectedDefaultDoctorId; // selectedDoctorId
	private Employee selectedDoctor;
	// for assign read only doctors to patient
	private List<PatientAssignment> retrievedReadOnlyDoctorIds;
	private String[] selectedReadOnlyDoctorIds;
	private List<Employee> retrievedReadOnlyDoctors;

	// Used for search patient by name
	private String selectedPatientName;

	// Used for search patient by lastVisitTime
	private String lastVisitDate;

	// Used for search patient by ohip
	private Map<String, String> searchTypMap;
	private String selectedOhip;
	private int searchType;
	private String searchContent;
	private String value;
	private String key;

	public String getSelectedPatientName() {
		return selectedPatientName;
	}

	public void setSelectedPatientName(String selectedPatientName) {
		this.selectedPatientName = selectedPatientName;
	}

	public String getLastVisitDate() {
		return lastVisitDate;
	}

	public void setLastVisitDate(String lastVisitDate) {
		this.lastVisitDate = lastVisitDate;
	}

	public String getSelectedOhip() {
		return selectedOhip;
	}

	public void setSelectedOhip(String selectedOhip) {
		this.selectedOhip = selectedOhip;
	}

	public Map<String, Object> getSession() {
		return session;
	}

	public Patient getRetrievedPatient() {
		return retrievedPatient;
	}

	public void setRetrievedPatient(Patient currentPatient) {
		this.retrievedPatient = currentPatient;
	}

	public String getActionMode() {
		return actionMode;
	}

	public void setActionMode(String actionMode) {
		this.actionMode = actionMode;
	}

	@Override
	public void setSession(Map session) {
		this.session = session;
	}

	@Override
	public void setRequest(Map arg0) {

	}

	public String initPatientViewPage() {
		session.put("triggeredAction", "initPatientViewPage");
		this.actionMode = "view";
		PatientDAO pDAO = new PatientDAOImpl();
		EmployeeDAOImpl eDao = new EmployeeDAOImpl();
		int retrievedPatientId = Integer.valueOf(this.selectedPatientId);
		// this.retrievedPatient = new Patient();
		try {
			this.retrievedPatient = pDAO.getPatientById(retrievedPatientId);
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERROR;
		}

		// retrieve all read only doctors
		this.retrievedReadOnlyDoctors = new ArrayList<Employee>();
		Employee doctor = new Employee();
		for (PatientAssignment pa : this.retrievedPatient
				.getPatientAssignmentSet()) {
			if (pa.getPermission() != 0) {
				try {
					doctor = eDao.getEmployeeById(pa.getDoctorId());
				} catch (DAOException e) {
					e.printStackTrace();
					return ERROR;
				}
				this.retrievedReadOnlyDoctors.add(doctor);
			}
		}
		session.put("actionResult","");
		// this.retrievedPatient = retrievedPatient;
		return SUCCESS;
	}

	public String initPatientCreatePage() {
		session.put("triggeredAction", "initPatientCreatePage");
		this.actionMode = "create";
		EmployeeDAO eDAO = new EmployeeDAOImpl();
		Employee retrievedStaff = new Employee();
		int retrieveEmployeeId = Integer.valueOf(this.selectedEmployeeId);
		try {
			retrievedStaff = eDAO.getEmployeeById(retrieveEmployeeId);
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		WorkForDAO wDAO = new WorkForDAOImpl();
		List<Employee> retrievedDoctorList = new ArrayList<Employee>();
		try {
			retrievedDoctorList = wDAO.getDoctorList(retrievedStaff);
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.retrievedPatient = new Patient();
		this.retrievedDoctors = retrievedDoctorList;
		session.put("actionResult","");
		return SUCCESS;
	}

	public String initPatientUpdatePage() {
		session.put("triggeredAction", "initPatientUpdatePage");

		PatientUtilImpl pui = new PatientUtilImpl();
		PatientDAOImpl pDAO = new PatientDAOImpl();
		PatientAssignmentDAOImpl paDao = new PatientAssignmentDAOImpl();
		EmployeeDAOImpl eDao = new EmployeeDAOImpl();
		int retrievePatientId = Integer.valueOf(this.selectedPatientId);
		Patient retrievePatient = new Patient();

		try {
			retrievePatient = pDAO.getPatientById(retrievePatientId);
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.retrievedPatient = retrievePatient;

		// get patient's default doctor
		Employee defaultDoctor = new Employee();
		defaultDoctor = pui.getDefaultDoctorByPatientId(this.retrievedPatient
				.getId());
		this.defaultDoctor = defaultDoctor;

		User currentUser = (User) session.get("currentUser");
		if (currentUser.getType() == 0) {// patient update its own information
											// (phone, address)
			this.actionMode = "patientUpdate";
		} else if (currentUser.getType() == 1) {// doctor update patient
												// information(assign patient to
												// doctor)
			this.actionMode = "doctorUpdate";

			try {
				// this.retrievedDoctors = eDao.getAllEmployee("DOCTOR");
				this.retrievedDoctors = paDao
						.getAllNotAssignedDoctorListForPatient(retrievePatient);
			} catch (DAOException e) {
				e.printStackTrace();
				return ERROR;
			}
			this.retrievedReadOnlyDoctorIds = new ArrayList<PatientAssignment>();
			for (PatientAssignment pa : retrievePatient
					.getPatientAssignmentSet()) {
				if (pa.getPermission() == 1) {
					this.retrievedReadOnlyDoctorIds.add(pa);
				}
			}
		} else if (currentUser.getType() == 2) {// staff update patient
												// information (SIN, Ohip, etc)
			this.actionMode = "staffUpdate";
			EmployeeDAO eDAO = new EmployeeDAOImpl();
			Employee retrievedStaff = new Employee();
			int retrieveEmployeeId = Integer.valueOf(this.selectedEmployeeId);
			try {
				retrievedStaff = eDAO.getEmployeeById(retrieveEmployeeId);
			} catch (DAOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			WorkForDAO wDAO = new WorkForDAOImpl();
			List<Employee> retrievedDoctorList = new ArrayList<Employee>();
			try {
				retrievedDoctorList = wDAO.getDoctorList(retrievedStaff);
			} catch (DAOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			this.retrievedDoctors = retrievedDoctorList;

		}

		session.put("actionResult","");
		return SUCCESS;
	}

	public String initPatientListPage() {
		session.put("triggeredAction", "initPatientListPage");
		Integer employeeId = Integer.valueOf(this.selectedEmployeeId);
		EmployeeDAOImpl eDao = new EmployeeDAOImpl();
		PatientAssignmentDAOImpl paDao = new PatientAssignmentDAOImpl();
		PatientUtilImpl pUtil = new PatientUtilImpl();
		Employee employee = new Employee();

		List<Patient> patientList = new ArrayList<Patient>();
		try {
			employee = eDao.getEmployeeById(employeeId);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}

		if (employee.getType() == 1) {// employee is a doctor
			this.actionMode = "showDoctorPatient";
			try {
				this.ownerPatients = paDao.getPatientByDoctorBelongTo(employee);
			} catch (DAOException e) {
				e.printStackTrace();
				return ERROR;
			}
			try {
				patientList = paDao.getPatientByDoctorReadOnly(employee);
				PatientUtilImpl pui = new PatientUtilImpl();
				Employee defaultDoctor = new Employee();
				this.viewerPatients = new HashMap<Patient, Employee>();
				for (Patient patient : patientList) {
					
					defaultDoctor = pui.getDefaultDoctorByPatientId(patient
							.getId());
					if (defaultDoctor == null) {
						defaultDoctor = new Employee();
						defaultDoctor.setName("No default doctor");
					}
					this.viewerPatients.put(patient, defaultDoctor);
				}
			} catch (DAOException e) {
				e.printStackTrace();
				return ERROR;
			}

		} else if (employee.getType() == 2) {// employee is a staff
			this.actionMode = "showStaffPatient";
			try {
				this.ownerPatients = pUtil.getPatientByStaffBelongTo(employee);
			} catch (DAOException e) {
				e.printStackTrace();
				return ERROR;
			}
		}
		return SUCCESS;
	}

	public String createPatient() {
		session.put("triggeredAction", "createPatient");
		PatientDAOImpl pDao = new PatientDAOImpl();
		PatientUtilImpl pui = new PatientUtilImpl();
		EmployeeDAOImpl eDao = new EmployeeDAOImpl();
		Patient newPatient = new Patient();
		try {
			this.defaultDoctor = eDao.getEmployeeById(Integer
					.valueOf(selectedDefaultDoctorId));
		} catch (DAOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return ERROR;
		}
		newPatient.setUsername(retrievedPatient.getUsername());
		newPatient.setPassword(retrievedPatient.getPassword());
		newPatient.setName(retrievedPatient.getName());
		newPatient.setCurrentHealth("No data");
		newPatient.setAddress(retrievedPatient.getAddress());
		newPatient.setPhone(retrievedPatient.getPhone());
		newPatient.setSin(retrievedPatient.getSin());
		newPatient.setOhip(retrievedPatient.getOhip());

		try {
			Integer patientId = pDao.createPatient(newPatient);
			retrievedPatient.setId(patientId);
		} catch (DAOException e) {
			e.printStackTrace();
			this.initPatientCreatePage();
			this.retrievedPatient = newPatient;
			session.put("actionResult",e.getMessage());
			return ERROR;
		}

		// create default patient assignment
		PatientAssignmentDAO pAssi = new PatientAssignmentDAOImpl();
		try {
			pAssi.CreatePatientAssignment(this.defaultDoctor, newPatient,
					(byte) 0);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}
		session.put("actionResult","Patient "+newPatient.getName()+" successfully created !!");
		this.actionMode = "createPatient";
		return SUCCESS;
	}

	public Employee getSelectedDoctor() {
		return selectedDoctor;
	}

	public void setSelectedDoctor(Employee selectedDoctor) {
		this.selectedDoctor = selectedDoctor;
	}

	public String updatePatientInfo() {
		session.put("triggeredAction", "updatePatientInfo");

		PatientDAOImpl pDao = new PatientDAOImpl();
		PatientUtilImpl pui = new PatientUtilImpl();
		PatientAssignmentDAOImpl paDao = new PatientAssignmentDAOImpl();
		Patient oldPatient = new Patient();
		EmployeeDAOImpl eDao = new EmployeeDAOImpl();
		Employee defaultDoctor = new Employee();

		try {
			oldPatient = pDao.getPatientById(this.retrievedPatient.getId());
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}

		defaultDoctor = pui.getDefaultDoctorByPatientId(oldPatient.getId());

		if (this.actionMode.equals("patientUpdate")) {// patient update its own
														// information (phone,
														// address)
			oldPatient.setAddress(retrievedPatient.getAddress());
			oldPatient.setPhone(retrievedPatient.getPhone());
			if (retrievedPatient.getPassword().length() != 0) {
				oldPatient.setPassword(retrievedPatient.getPassword());
			}
			this.session.put("currentUser", oldPatient);
			this.actionMode = "patientView";
		} else if (this.actionMode.equals("doctorUpdate")) {// doctor update patient information(assign patient to doctor)
			
			oldPatient.setCurrentHealth(retrievedPatient.getCurrentHealth());
			// remove duplicate entry

			// first, delete all origin readOnly doctor assignments
			Set<PatientAssignment> paSet = oldPatient.getPatientAssignmentSet();

			for (PatientAssignment pa : paSet) {
				if (pa.getPermission() == 1) {
					try {
						paDao.deletePatientAssignmentByAssignment(pa);
					} catch (DAOException e) {
						e.printStackTrace();
						return ERROR;
					}
				}
			}

			// second, create new assignments
			if(this.selectedReadOnlyDoctorIds != null){
				List<String> doctorIdList = Arrays.asList(this.selectedReadOnlyDoctorIds);
				Set<String> doctorIdSet = new HashSet<String>(doctorIdList);
				for (String s : doctorIdSet) {
					if (Integer.valueOf(s) != defaultDoctor.getId()) {
						PatientAssignment pa = new PatientAssignment();
						pa.setPatientId(oldPatient.getId());
						pa.setDoctorId(Integer.valueOf(s));
						pa.setPermission((byte) 1);
						try {
							paDao.createPatientAssignmentByAssignment(pa);
						} catch (DAOException e) {
							e.printStackTrace();
							return ERROR;
						}
					}
				}
			}
			this.actionMode = "doctorView";
		} else if (this.actionMode.equals("staffUpdate")) {// staff update
															// patient
															// information (SIN,
															// Ohip, etc)
			oldPatient.setName(retrievedPatient.getName());
			oldPatient.setAddress(retrievedPatient.getAddress());
			oldPatient.setPhone(retrievedPatient.getPhone());
			oldPatient.setSin(retrievedPatient.getSin());
			oldPatient.setOhip(retrievedPatient.getOhip());

			// delete origin defaultDoctor if changed
			Integer defaultDoctorId = Integer.valueOf(selectedDefaultDoctorId);
			try {
				this.defaultDoctor = eDao.getEmployeeById(defaultDoctorId);
			} catch (DAOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return ERROR;
			}

			boolean defaultChanged = false;
			for (PatientAssignment pa : oldPatient.getPatientAssignmentSet()) {
				if (pa.getPermission() == 0
						&& pa.getDoctorId() != defaultDoctorId) {
					try {
						paDao.deletePatientAssignmentByAssignment(pa);
						defaultChanged = true;
					} catch (DAOException e) {
						e.printStackTrace();
					}
				}
			}
			// create new default patient assignment if changed
			if (defaultChanged) {
				try {
					paDao.CreatePatientAssignment(this.defaultDoctor,
							oldPatient, (byte) 0);
				} catch (DAOException e) {
					e.printStackTrace();
					return ERROR;
				}
			}
			this.actionMode = "staffView";
		}

		// update patient information
		try {
			pDao.updatePatient(oldPatient);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}
		// retrieved updated patient information
		Patient newPatient = new Patient();
		try {
			newPatient = pDao.getPatientById(oldPatient.getId());
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}
		
		this.retrievedPatient = newPatient;
		// get patient's default doctor
		defaultDoctor = pui.getDefaultDoctorByPatientId(this.retrievedPatient
				.getId());
		this.defaultDoctor = defaultDoctor;

		// retrieve all read only doctors
		this.retrievedReadOnlyDoctors = new ArrayList<Employee>();
		Employee doctor = new Employee();
		for (PatientAssignment pa : this.retrievedPatient
				.getPatientAssignmentSet()) {
			if (pa.getPermission() != 0) {
				try {
					doctor = eDao.getEmployeeById(pa.getDoctorId());
				} catch (DAOException e) {
					e.printStackTrace();
					return ERROR;
				}
				this.retrievedReadOnlyDoctors.add(doctor);
			}
		}
		session.put("actionResult","Patient "+newPatient.getName()+" successfully updated !!");
		return SUCCESS;
	}

	public Map<String, String> getSearchTypeMap() {
		Map<String, String> searchTypeMap = new HashMap<String, String>();
		searchTypeMap.put("1", "Ohip");
		// searchTypeMap.put("1","LastVisitTime");
		searchTypeMap.put("0", "Name");
		return searchTypeMap;
	}

	public String searchPatient() {
		session.put("triggeredAction", "searchPatient");
		this.actionMode = "searchPatient";
		System.out.print("in searchPatient");
		String doctorId = this.selectedEmployeeId;
		PatientAssignmentDAOImpl paDao = new PatientAssignmentDAOImpl();
		List<Patient> patientList = new ArrayList<Patient>();

		this.actionMode = "showDoctorPatient";

		try {
			patientList = paDao.searchBelongToPatientForDoctor(doctorId,
					searchType, searchContent);
		} catch (DAOException e) {
			e.printStackTrace();
			
		}
		this.ownerPatients = patientList;
		

		try {
			patientList = paDao.searchReadOnlyPatientForDoctor(doctorId,
					searchType, searchContent);
		} catch (DAOException e) {
			e.printStackTrace();
			return ERROR;
		}

		PatientUtilImpl pui = new PatientUtilImpl();
		Employee defaultDoctor = new Employee();
		this.viewerPatients = new HashMap<Patient, Employee>();
		for (Patient patient : patientList) {
			defaultDoctor = pui.getDefaultDoctorByPatientId(patient.getId());
			if (defaultDoctor == null) {
				defaultDoctor = new Employee();
				defaultDoctor.setName("No default doctor");
			}
			this.viewerPatients.put(patient, defaultDoctor);
		}

		return SUCCESS;
	}

	public String searchPatientByLastVisitDate() {

		try {

			PatientAssignmentDAOImpl paDao = new PatientAssignmentDAOImpl();
//			List<Patient> patientList = new ArrayList<Patient>();
			DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
			java.util.Date lastVisitUtilDate = new java.util.Date();
			lastVisitUtilDate = formatter.parse(lastVisitDate);
			Date lastVisitSQLDate = new java.sql.Date(
					lastVisitUtilDate.getTime());
			Employee doctor = new Employee();
			doctor = (Employee) session.get("currentUser");
			this.ownerPatients = new ArrayList<Patient>();
			this.ownerPatients = paDao
					.searchBelongToPatientForDoctorByLastVisitDate(doctor,
							lastVisitSQLDate);

			List<Patient> viewOnlyPatientList = new ArrayList<Patient>();
			viewOnlyPatientList = paDao.searchReadOnlyPatientForDoctorByLastVisitDate(doctor,lastVisitSQLDate);

			PatientUtilImpl pui = new PatientUtilImpl();
			Employee defaultDoctor = new Employee();
			this.viewerPatients = new HashMap<Patient, Employee>();
			for (Patient patient : viewOnlyPatientList) {
				defaultDoctor = pui
						.getDefaultDoctorByPatientId(patient.getId());
				if (defaultDoctor == null) {
					defaultDoctor = new Employee();
					defaultDoctor.setName("No default doctor");
				}
				this.viewerPatients.put(patient, defaultDoctor);
			}

			this.actionMode = "showDoctorPatient";
		} catch (Exception e) {
			e.printStackTrace();
			return ERROR;
		}

		return SUCCESS;
	}

	public int getSearchType() {
		return searchType;
	}

	public void setSearchType(int searchType) {
		this.searchType = searchType;
	}

	public Employee getDefaultDoctor() {
		return defaultDoctor;
	}

	public void setDefaultDoctor(Employee defaultDoctor) {
		this.defaultDoctor = defaultDoctor;
	}

	public String getSelectedPatientId() {
		return selectedPatientId;
	}

	public void setSelectedPatientId(String selectedPatientId) {
		this.selectedPatientId = selectedPatientId;
	}

	public String getSelectedEmployeeId() {
		return selectedEmployeeId;
	}

	public void setSelectedEmployeeId(String selectedEmployeeId) {
		this.selectedEmployeeId = selectedEmployeeId;
	}

	public List<Patient> getOwnerPatients() {
		return ownerPatients;
	}

	public void setOwnerPatients(List<Patient> ownerPatients) {
		this.ownerPatients = ownerPatients;
	}

	public Map<Patient, Employee> getViewerPatients() {
		return viewerPatients;
	}

	public void setViewerPatients(Map<Patient, Employee> viewerPatients) {
		this.viewerPatients = viewerPatients;
	}

	public List<Employee> getRetrievedDoctors() {
		return retrievedDoctors;
	}

	public void setRetrievedDoctors(List<Employee> retrievedDoctors) {
		this.retrievedDoctors = retrievedDoctors;
	}

	public String getSelectedDefaultDoctorId() {
		return selectedDefaultDoctorId;
	}

	public void setSelectedDefaultDoctorId(String selectedDefaultDoctorId) {
		this.selectedDefaultDoctorId = selectedDefaultDoctorId;
	}

	public void setSearchTypMap(Map<String, String> searchTypMap) {
		this.searchTypMap = searchTypMap;
	}

	public List<PatientAssignment> getRetrievedReadOnlyDoctorIds() {
		return retrievedReadOnlyDoctorIds;
	}

	public void setRetrievedReadOnlyDoctorIds(
			List<PatientAssignment> retrievedReadOnlyDoctorIds) {
		this.retrievedReadOnlyDoctorIds = retrievedReadOnlyDoctorIds;
	}

	public String[] getSelectedReadOnlyDoctorIds() {
		return selectedReadOnlyDoctorIds;
	}

	public void setSelectedReadOnlyDoctorIds(String[] selectedReadOnlyDoctorIds) {
		this.selectedReadOnlyDoctorIds = selectedReadOnlyDoctorIds;
	}

	public List<Employee> getRetrievedReadOnlyDoctors() {
		return retrievedReadOnlyDoctors;
	}

	public void setRetrievedReadOnlyDoctors(
			List<Employee> retrievedReadOnlyDoctors) {
		this.retrievedReadOnlyDoctors = retrievedReadOnlyDoctors;
	}

}
